package com.ems.config;

import java.util.Date;
import java.util.Map;
import java.util.Random;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.ems.common.RedisPool;
import com.ems.common.ServiceException;
import com.ems.constants.RedisCons;
import com.ems.entity.ConfigEquRun;
import com.ems.entity.ConfigMode;
import com.ems.entity.EquPower;
import com.ems.entity.StoredEqu;
import com.ems.enums.EquTypeEnum;
import com.ems.mapper.ConfigEquRunMapper;
import com.ems.mapper.ConfigModeMapper;
import com.ems.mapper.EquPowerMapper;
import com.ems.service.PeakValleyService;
import com.ems.utils.DateUtil;

/**
 * 多线程定时任务配置
 * 
 * @author chenzhao @date Oct 23, 2019
 */
@EnableScheduling // 开启定时任务
@EnableAsync // 开启多线程
@Component
public class MultiThreadScheduleTask {
	private static Logger log = LoggerFactory.getLogger(MultiThreadScheduleTask.class);

	@Autowired
	EquPowerMapper equPowerMapper;
	@Autowired
	ConfigModeMapper configModeMapper;
	@Autowired
	ConfigEquRunMapper configEquRunMapper;

	String equId = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 25);

	@Async
	@Scheduled(fixedDelay = 1000 * 60 * 1)
	public void insertCity() {
		EquPower equPower = new EquPower();
		ConfigEquRun configEquRun = new ConfigEquRun();
		equPower.setEquId(equId);
		equPower.setCollectTimestamp(new Date().getTime() + "");
		// (80%~90%)*180kW (60%~70%)*180kW >>> 108~126
		long energy = 0;
		if (isPeak()) {
			equPower.setPower(180000L * 8 + (long) (Math.random() * ((180000L * 9 - 180000L * 8) + 1)));
			energy = 10800 * 30 + (long) (Math.random() * ((10800 * 50 - 10800 * 30) + 1));
		} else {
			equPower.setPower(180000L * 6 + (long) (Math.random() * ((180000L * 7 - 180000L * 6) + 1)));
			energy = 10800 * 30 + (long) (Math.random() * ((10800 * 50 - 10800 * 30) + 1));
		}
		configEquRun.setRealTimeEnergy(energy);
		configEquRun.setRealTimeEnergyForward(energy);
		configEquRun.setRealTimeEnergyReverse(energy);

		long mockEquCount = updateConfigEquRun(EquTypeEnum.cityGrid.getCode(), configEquRun, equPower.getPower());
		RedisPool.incr(RedisCons.mockEquCount + EquTypeEnum.cityGrid.getCode());
		log.info("#mockEquCount:[{}]", mockEquCount);
		if (mockEquCount % 5 == 0) {// 每采集5次设备数据，持久化一次设备功率日志
			equPowerMapper.insertCity(equPower);
		}
	}

	private long updateConfigEquRun(String equType, ConfigEquRun configEquRun, long power) {
		long voltage0 = 21000 + (long) (Math.random() * ((23000 - 21000) + 1));
		long voltage1 = 21000 + (long) (Math.random() * ((23100 - 21000) + 1));
		long voltage2 = 21000 + (long) (Math.random() * ((23200 - 21000) + 1));

		configEquRun.setRealTimeVoltage0(
				configEquRun.getRealTimeVoltage0() <= 0 ? voltage0 : configEquRun.getRealTimeVoltage0());// 210~230V
		configEquRun.setRealTimeVoltage1(
				configEquRun.getRealTimeVoltage1() <= 0 ? voltage1 : configEquRun.getRealTimeVoltage1());// 210~231V
		configEquRun.setRealTimeVoltage2(
				configEquRun.getRealTimeVoltage2() <= 0 ? voltage2 : configEquRun.getRealTimeVoltage2());// 210~232V
		configEquRun.setRealTimeCurrent0(power / (voltage0 / 100));
		configEquRun.setRealTimeCurrent1(power / (voltage1 / 100));
		configEquRun.setRealTimeCurrent2(power / (voltage2 / 100));
		configEquRun.setRealTimePower(power);
		configEquRun.setRealTimePowerUseless(10000 + (long) (Math.random() * ((90000 - 10000) + 1)));
		configEquRun.setRealTimePowerView(Math.abs(power - configEquRun.getRealTimePowerUseless()));

		configEquRun.setType(equType);
		configEquRunMapper.update(configEquRun);
		long mockEquCount = Long.parseLong(RedisPool.get(RedisCons.mockEquCount + EquTypeEnum.cityGrid.getCode()));
		return mockEquCount;
	}

	private long updateConfigEquRun4stored(String equType, ConfigEquRun configEquRun, long power) {
		long voltage0 = 72000 + (long) (Math.random() * ((73600 - 72000) + 1));// 720~736V
		long voltage1 = 72000 + (long) (Math.random() * ((73600 - 72000) + 1));
		long voltage2 = 72000 + (long) (Math.random() * ((73600 - 72000) + 1));
		long current0 = 10000 + (long) (Math.random() * ((10000 - 14800) + 1));

		configEquRun.setRealTimeVoltage0(voltage0);
		configEquRun.setRealTimeVoltage1(voltage1);
		configEquRun.setRealTimeVoltage2(voltage2);
		configEquRun.setRealTimeCurrent0(current0);
		configEquRun.setRealTimeCurrent1(power / (voltage1 / 100));
		configEquRun.setRealTimeCurrent2(power / (voltage2 / 100));
		configEquRun.setRealTimePower(power);
		configEquRun.setRealTimePowerView(power - 100000L);
		configEquRun.setRealTimePowerUseless(100000L);

		configEquRun.setType(equType);
		configEquRunMapper.update(configEquRun);
		long mockEquCount = Long.parseLong(RedisPool.get(RedisCons.mockEquCount + EquTypeEnum.cityGrid.getCode()));
		return mockEquCount;
	}

	@Async
	@Scheduled(fixedDelay = 1000 * 60 * 1)
	public void insertPv() {
		EquPower equPower = new EquPower();
		ConfigEquRun configEquRun = new ConfigEquRun();
		equPower.setEquId(equId);
		equPower.setCollectTimestamp(new Date().getTime() + "");
		// (20%~80%)*180.28kW 0kW >>> (30%~60%)*50kW 0kW
		if (isPeak()) {
			equPower.setPower(50000L * 3 + (long) (Math.random() * ((50000L * 6 - 50000L * 3) + 1)));
		} else {
			equPower.setPower(0L);
		}

		long energy = 3500 * 10 + (long) (Math.random() * ((3500 * 20 - 3500 * 10) + 1));
		configEquRun.setRealTimeEnergy(energy);
		configEquRun.setRealTimeEnergyForward(energy);
		configEquRun.setRealTimeEnergyReverse(energy);
		configEquRun.setRealTimeVoltage0(22100L);// 光伏3相电压固定221V
		configEquRun.setRealTimeVoltage1(22100L);
		configEquRun.setRealTimeVoltage2(22100L);
		long mockEquCount = updateConfigEquRun(EquTypeEnum.PV.getCode(), configEquRun, equPower.getPower());
		if (mockEquCount % 5 == 0) {// 每采集5次设备数据，持久化一次设备功率日志
			equPowerMapper.insertPv(equPower);
		}
	}

	@Async
	@Scheduled(fixedDelay = 1000 * 60 * 1)
	public void insertStored() {
		StoredEqu storedEqu = new StoredEqu();
		ConfigEquRun configEquRun = new ConfigEquRun();
		storedEqu.setEquId(equId);
		storedEqu.setCollectTimestamp(new Date().getTime() + "");
		storedEqu.setChargeStatus(new Random().nextInt(2));// 随机0/1
		// (60%~80%)*100kW (60%~80%)*100kW >>>
		if (isPeak()) {
			storedEqu.setPower(100000L * 6 + (long) (Math.random() * ((100000L * 8 - 100000L * 6) + 1)));
		} else {
			storedEqu.setPower(100000L * 6 + (long) (Math.random() * ((100000L * 8 - 100000L * 6) + 1)));
		}
		long energy = 10800 * 20 + (long) (Math.random() * ((10800 * 30 - 10800 * 20) + 1));
		configEquRun.setRealTimeEnergy(energy);
		configEquRun.setRealTimeEnergyForward(energy);
		configEquRun.setRealTimeEnergyReverse(energy);
		configEquRun.setStoredChargeStatus(storedEqu.getChargeStatus() + "");

		long mockEquCount = updateConfigEquRun4stored(EquTypeEnum.storedEnergy.getCode(), configEquRun,
				storedEqu.getPower());
		if (mockEquCount % 5 == 0) {// 每采集5次设备数据，持久化一次设备功率日志
			equPowerMapper.insertStored(storedEqu);
		}
	}

	@Async
	@Scheduled(fixedDelay = 1000 * 60 * 1)
	public void insertHigntpower() {
		EquPower equPower = new EquPower();
		ConfigEquRun configEquRun = new ConfigEquRun();
		equPower.setEquId(equId);
		equPower.setCollectTimestamp(new Date().getTime() + "");
		// (20%~30%)*350.02kW 0 >>>
		if (isPeak()) {
			equPower.setPower(350020L * 2 + (long) (Math.random() * ((350020L * 3 - 350020L * 2) + 1)));
		} else {
			equPower.setPower(0);
		}
		long energy = 3000 * 30 + (long) (Math.random() * ((3000 * 60 - 3000 * 30) + 1));
		configEquRun.setRealTimeEnergy(energy);
		configEquRun.setRealTimeEnergyForward(energy);
		configEquRun.setRealTimeEnergyReverse(energy);
		long mockEquCount = updateConfigEquRun(EquTypeEnum.highPower.getCode(), configEquRun, equPower.getPower());
		if (mockEquCount % 5 == 0) {// 每采集5次设备数据，持久化一次设备功率日志
			equPowerMapper.insertHigntpower(equPower);
		}
	}

	@Async
	@Scheduled(fixedDelay = 1000 * 60 * 1)
	public void insertDc() {
		EquPower equPower = new EquPower();
		ConfigEquRun configEquRun = new ConfigEquRun();
		equPower.setEquId(equId);
		equPower.setCollectTimestamp(new Date().getTime() + "");
		// (20%~80%)*120.92kW 0 >>> (30%~60%)*60kW 0
		if (isPeak()) {
			equPower.setPower(60000L * 3 + (long) (Math.random() * ((60000L * 6 - 60000L * 3) + 1)));
		} else {
			equPower.setPower(0);
		}

		long energy = 9000 * 30 + (long) (Math.random() * ((9000 * 60 - 9000 * 30) + 1));
		configEquRun.setRealTimeEnergy(energy);
		configEquRun.setRealTimeEnergyForward(energy);
		configEquRun.setRealTimeEnergyReverse(energy);
		long mockEquCount = updateConfigEquRun(EquTypeEnum.DC.getCode(), configEquRun, equPower.getPower());
		if (mockEquCount % 5 == 0) {// 每采集5次设备数据，持久化一次设备功率日志
			equPowerMapper.insertDc(equPower);
		}
	}

	@Async
	@Scheduled(fixedDelay = 1000 * 60 * 1)
	public void insertAc() {
		EquPower equPower = new EquPower();
		ConfigEquRun configEquRun = new ConfigEquRun();
		equPower.setEquId(equId);
		equPower.setCollectTimestamp(new Date().getTime() + "");
		// (20%~80%)*10kW 0 >>> (20%~80%)*7kW 0
		if (isPeak()) {
			equPower.setPower(7000L * 2 + (long) (Math.random() * ((7000L * 8 - 7000L * 2) + 1)));
		} else {
			equPower.setPower(0);
		}

		long energy = 9000 * 30 + (long) (Math.random() * ((9000 * 60 - 9000 * 30) + 1));
		configEquRun.setRealTimeEnergy(energy);
		configEquRun.setRealTimeEnergyForward(energy);
		configEquRun.setRealTimeEnergyReverse(energy);
		long mockEquCount = updateConfigEquRun(EquTypeEnum.AC.getCode(), configEquRun, equPower.getPower());
		if (mockEquCount % 5 == 0) {// 每采集5次设备数据，持久化一次设备功率日志
			equPowerMapper.insertAc(equPower);
		}
	}

	@Async
	@Scheduled(fixedDelay = 1000 * 60 * 1)
	public void updateV2L() {
		EquPower equPower = new EquPower();
		ConfigEquRun configEquRun = new ConfigEquRun();
		equPower.setEquId(equId);
		equPower.setCollectTimestamp(new Date().getTime() + "");
		// (0%~80%)*60.58kW (0%~80%)*60.58kW>>>
		if (isPeak()) {
			equPower.setPower(60580L * 0 + (long) (Math.random() * ((60580L * 8 - 60580L * 0) + 1)));
		} else {
			equPower.setPower(60580L * 0 + (long) (Math.random() * ((60580L * 8 - 60580L * 0) + 1)));
		}
		long energy = 0 + (long) (Math.random() * ((3000 * 10 - 0) + 1));
		configEquRun.setRealTimeEnergy(energy);
		configEquRun.setRealTimeEnergyForward(energy);
		configEquRun.setRealTimeEnergyReverse(energy);
		updateConfigEquRun(EquTypeEnum.V2L.getCode(), configEquRun, equPower.getPower());
	}

	@Async
	@Scheduled(fixedDelay = 1000 * 60 * 1)
	public void updateNormalLoad() {
		EquPower equPower = new EquPower();
		ConfigEquRun configEquRun = new ConfigEquRun();
		equPower.setEquId(equId);
		equPower.setCollectTimestamp(new Date().getTime() + "");
		// (0%~80%)*10kW (0%~80%)*10kW >>> (30%~60%)*60kW (30%~60%)*60kW
		if (isPeak()) {
			equPower.setPower(60000L * 3 + (long) (Math.random() * ((60000L * 6 - 60000L * 3) + 1)));
		} else {
			equPower.setPower(60000L * 3 + (long) (Math.random() * ((60000L * 6 - 60000L * 3) + 1)));
		}
		long energy = 3000 * 30 + (long) (Math.random() * ((3000 * 60 - 3000 * 30) + 1));
		configEquRun.setRealTimeEnergy(energy);
		configEquRun.setRealTimeEnergyForward(energy);
		configEquRun.setRealTimeEnergyReverse(energy);
		updateConfigEquRun(EquTypeEnum.normalLoad.getCode(), configEquRun, equPower.getPower());
	}

	@Async
	@Scheduled(fixedDelay = 1000 * 60 * 1)
	public void updateACDC() {
		EquPower equPower = new EquPower();
		ConfigEquRun configEquRun = new ConfigEquRun();
		equPower.setEquId(equId);
		equPower.setCollectTimestamp(new Date().getTime() + "");
		// (20%~80%)*120.2kW (20%~80%)*120.2kW >>>
		if (isPeak()) {
			equPower.setPower(120200L * 2 + (long) (Math.random() * ((120200L * 8 - 120200L * 2) + 1)));
		} else {
			equPower.setPower(120200L * 2 + (long) (Math.random() * ((120200L * 8 - 120200L * 2) + 1)));
		}
		long energy = 3000 * 30 + (long) (Math.random() * ((3000 * 60 - 3000 * 30) + 1));
		configEquRun.setRealTimeEnergy(energy);
		configEquRun.setRealTimeEnergyForward(energy);
		configEquRun.setRealTimeEnergyReverse(energy);
		updateConfigEquRun(EquTypeEnum.ACDC.getCode(), configEquRun, equPower.getPower());
	}

	@Async
	@Scheduled(fixedDelay = 1000 * 60 * 1)
	public void peakValleyTime() throws Exception {
		ConfigMode valleyTime = configModeMapper.selectOne("peakSuppression", "valleyInterval");
		ConfigMode peakTime = configModeMapper.selectOne("peakSuppression", "peakInterval");
		ConfigMode normallTime = configModeMapper.selectOne("peakSuppression", "normalInterval");
		ConfigMode A0 = configModeMapper.selectOne("peakShaving", "A0");
		ConfigMode A1 = configModeMapper.selectOne("peakShaving", "A1");
		ConfigMode A2 = configModeMapper.selectOne("peakShaving", "A2");
		ConfigMode A3 = configModeMapper.selectOne("peakShaving", "A3");
		ConfigMode W1 = configModeMapper.selectOne("peakShaving", "W1");
		ConfigMode W2 = configModeMapper.selectOne("peakShaving", "W2");
		ConfigMode W8 = configModeMapper.selectOne("peakShaving", "W8");
		ConfigMode W9 = configModeMapper.selectOne("peakShaving", "W9");
		ConfigMode W10 = configModeMapper.selectOne("peakShaving", "W10");
		if (valleyTime == null || peakTime == null || normallTime == null) {
			throw new ServiceException("#谷电、峰电、普通时间区间-未配置");
		}
		if (A0 == null || A1 == null || W1 == null || W2 == null || W8 == null || W9 == null || W10 == null) {
			throw new ServiceException("#A0、A1、W1、W2、W8、W9、W10-未配置完整");
		}
		String valleyInterval = valleyTime.getValue();// 0:00:00-5:59:59 {单区间！！！！！！！！！}
		String peakInterval1 = peakTime.getValue().split(",")[0];// 8:00:00-11:59:59,18:00:00-21:59:59 {双区间！！！！！！！！！}
		String peakInterval2 = peakTime.getValue().split(",")[1];
//		String normallInterval = normallTime.getValue();// 6:00:00-7:59:59,12:00:00-17:59:59,22:00:00-23:59:59

		Map<String, Object> storedMap = configEquRunMapper.selectStored();
		Map<String, Object> cityMap = configEquRunMapper.selectCtiy();
		long storedSoc = Long.parseLong(storedMap.get("storedSoc") + "");
		long cityPower = Long.parseLong(cityMap.get("realTimePower") + "");
		String nowDayStr = DateUtil.getSdf("yyyy-MM-dd").format(new Date());// yyyy-MM-dd HH:mm:ss
		if (DateUtil.validateValidDate(nowDayStr + " " + valleyInterval.split("-")[0],
				nowDayStr + " " + valleyInterval.split("-")[1])) {
			/** 谷电时间区间 0:00:00-5:59:59 **********************************/
			/*
			 * 谷电（） 1、当储能（BMS的soc）高于A1低于A0，储能可充可放， 1）市电功率供电区间为W1-W2，
			 * 2）低于W1时，优先调低PCS（ACDC的功率）供电功率直至0，再调整PCS充电功率直至W10，再调低光伏输出功率直至0；
			 * 3）当高于W2时，优先调高光伏供电功率直至W8，继续调低PCS充电功率/调高PCS供电功率直至W9。
			 * 4）保障常规负载，限制AC、DC桩接入，使得全部负载额定功率需小于等于W2+W9；
			 * 
			 * 2、当储能低于A1，调低储能供电功率直至0，储能只充不放，市电功率输出区间为W1-W2，低于W1时，优先调高PCS充电功率直至W10，
			 * 再调低光伏输出功率直至0；当高于W2时，优先调高光伏输出功率直至W8，再调低PCS充电功率直至0；保障常规负载，限制AC、DC桩接入，
			 * 全部负载额定功率需小于等于W2；
			 * 
			 * 3、储能超过最大阈值A0，调低PCS充电功率直至0，储能只放不充，市电功率输出区间为W1-W2，低于W1时，调低PCS供电功率直至0，
			 * 再调低光伏输出功率直至0；当高于W2时，优先调高光伏输出功率直至W8，再调高PCS供电功率至W9；保障常规负载，限制AC、DC桩接入，
			 * 全部负载额定功率需小于等于W2+W9；
			 */
			log.info("#当前处于谷电时间区间，开始消峰填谷策略分析，#valleyTime配置:{}，#当前时间:{}", valleyTime.getValue(),
					DateUtil.getSdf("yyyy-MM-dd HH:mm:ss").format(new Date()));
			PeakValleyService.valleyInterval(A0, A1, W1, W2, storedSoc, cityPower);
		} else if (DateUtil.validateValidDate(nowDayStr + " " + peakInterval1.split("-")[0],
				nowDayStr + " " + peakInterval1.split("-")[1])
				|| DateUtil.validateValidDate(nowDayStr + " " + peakInterval2.split("-")[0],
						nowDayStr + " " + peakInterval2.split("-")[1])) {
			/** 峰电时间区间 8:00:00-11:59:59,18:00:00-21:59:59 ********************************/
			/*
			 * 峰电（8：00~11：00 18：00~21：00）
			 * 1、当储能高于A3，储能只放不充，市电功率供电区间为W1-W2，低于W1时，优先调低PCS供电功率直至0，再调低光伏输出功率直至0；当高于W2时，
			 * 优先调高光伏供电功率直至W8，继续调高PCS供电功率直至W9。保障常规负载，限制AC、DC桩接入，使得全部负载额定功率需小于等于W2+W9；
			 * 
			 * 2、当储能低于A3，调低储能供电功率直至0，储能不充不放，市电功率输出区间为W1-W6，低于W1时，调低光伏输出功率直至0；当高于W2时，
			 * 优先调高光伏输出功率直至W8；保障常规负载，限制AC、DC桩接入，全部负载额定功率需小于等于W2；
			 */
			log.info("#当前处于谷电时间区间，开始消峰填谷策略分析，#peakTime配置:{}，#当前时间:{}", peakTime.getValue(),
					DateUtil.getSdf("yyyy-MM-dd HH:mm:ss").format(new Date()));
			PeakValleyService.peakInterval(A3, W1, W2, storedSoc, cityPower);
		} else {
			/** 平电时间区间 *******************************************************/
			/*
			 * 平电（6：00~8：00 11：00~18：00 21：00~22：00）
			 * 1、当储能高于A2，储能可充可放，市电功率供电区间为W1-W2，低于W1时，优先调低PCS供电功率直至0，再调低光伏输出功率直至0；当高于W2时，
			 * 优先调高光伏供电功率直至W8，继续调高PCS供电功率直至W9。保障常规负载，限制AC、DC桩接入，使得全部负载额定功率需小于等于W2+W9；
			 * 
			 * 2、当储能低于A2且高于A3，调低储能供电功率直至0（不充不放），市电功率输出区间为W1-W2，低于W1时，调低光伏输出功率直至0；当高于W2时，
			 * 优先调高光伏输出功率直至W8；保障常规负载，限制AC、DC桩接入，全部负载额定功率需小于等于W2；
			 * 
			 * 3、当储能低于A3，储能只充不放，市电功率供电区间为W1-W2，低于W1时，调高PCS充电功率直至W10，再调低光伏输出功率直至0；当高于W2时，
			 * 优先调高光伏供电功率直至W8，继续调低PCS充电功率至0。保障常规负载，限制AC、DC桩接入，使得全部负载额定功率需小于等于W2；
			 */
			log.info("#当前处于平电时间区间，开始消峰填谷策略分析，#normallTime配置:{}，#当前时间:{}", normallTime.getValue(),
					DateUtil.getSdf("yyyy-MM-dd HH:mm:ss").format(new Date()));
			PeakValleyService.normallInterval(A2, A3, W1, W2, storedSoc, cityPower);
		}

	}

	private boolean isPeak() {
		long mockEquCount = Long.parseLong(RedisPool.get(RedisCons.mockEquCount + EquTypeEnum.cityGrid.getCode()));
		if (mockEquCount % 2 == 0) {
			return true;
		} else {
			return false;
		}
	}

	public static void main(String[] args) {
		System.out.println(new Random().nextInt(2));
		System.out.println(5 + (long) (Math.random() * ((10 - 5) + 1)));
		System.out.println(0 + (long) (Math.random() * ((10000L * 8 - 0) + 1)));
		System.out.println(180000 / ((21000 + (long) (Math.random() * ((21000 - 23000) + 1))) / 100));
		System.out.println(65 % 5);
		System.out.println(new Date().getHours());
	}
}